package edu.ivanov.apm.ui;

import edu.ivanov.apm.chaos.*;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.AnchorPane;

/**
 * User: ilya
 * Date: 12.10.13
 * Time: 9:04
 */
public class FractalBoard extends DrawBoard {

	private static final int CANVAS_PADDING_X = 10;
	private static final int CANVAS_PADDING_Y = 10;

    private RuleProducer producer;
    private int iterations;
    private double step;
    private double rotateAngle;

    private TabPane tabPane = new TabPane();

    /**
     * @param producer Генератор правил для рисования фрактала.
     * @param iterations Число итераций, которое необходимо выполнить.
     */
    public FractalBoard(RuleProducer producer, int iterations) {
        if (producer == null)
            throw new RuntimeException("Не задан генератор правил для рисования фрактала");
        if (producer.getAxiom() == null)
            throw new RuntimeException("Не задана аксиома для получения правил");
        if (iterations < 1)
            throw new RuntimeException("Число итераций должно быть положительным");

        this.producer = producer;
        this.iterations = iterations;

        getChildren().add(tabPane);
	    setAnchor(tabPane, 10);
    }

    public void setStep(double step) {
        this.step = step;
    }

    public void setRotateAngle(double rotateAngle) {
        this.rotateAngle = rotateAngle;
    }

    public void draw() {
	    tabPane.getTabs().clear();

        String rule = producer.getAxiom();
        Interpreter interpreter = new Interpreter();
	    interpreter.setF(step);
	    interpreter.setTheta(rotateAngle);

        for (int i = 0; i < iterations; i++) {
            rule = producer.produce(rule);

	        // Оцениваем границы фрактала на плоскости.
	        interpreter.setTurtle(new Turtle());
            MotionBounds bounds = interpreter.interpret(rule);

	        // Смещаем полученный прямоугольник в начало координат (с зазором).
	        Position topLeft = bounds.getTopLeft();
	        double dx = CANVAS_PADDING_X - topLeft.getX();
	        double dy = CANVAS_PADDING_Y - topLeft.getY();

	        // Определяем размеры канвы и начальное положение черепашки.
	        Position oldInitial = bounds.getInitial();
	        Position initial = new Position(oldInitial.getX() + dx, oldInitial.getY() + dy, oldInitial.getAlpha());

	        Position bottomRight = bounds.getBottomRight();
	        double canvasWidth = bottomRight.getX() + dx + CANVAS_PADDING_X;
	        double canvasHeight = bottomRight.getY() + dy + CANVAS_PADDING_Y;

	        // Создаём канву. Добавляем её на таб с прокруткой.
	        Canvas canvas = new Canvas(canvasWidth, canvasHeight);

	        ScrollPane canvasScroller = new ScrollPane();
	        canvasScroller.setContent(canvas);

	        AnchorPane canvasAnchor = new AnchorPane();
	        canvasAnchor.getChildren().add(canvasScroller);
	        setAnchor(canvasScroller, 5);

	        Tab tab = new Tab(String.format("Итерация %d", i + 1));
	        tab.setContent(canvasAnchor);
	        tab.setClosable(false);

	        tabPane.getTabs().add(tab);

	        // Рисуем фрактал.
	        PaintingTurtle turtle = new PaintingTurtle(canvas);
	        turtle.setPosition(initial);
	        interpreter.setTurtle(turtle);
	        interpreter.interpret(rule);
        }
    }

	private static void setAnchor(Node node, double padding) {
		AnchorPane.setLeftAnchor(node, padding);
		AnchorPane.setTopAnchor(node, padding);
		AnchorPane.setRightAnchor(node, padding);
		AnchorPane.setBottomAnchor(node, padding);
	}
}
